/*=================================================================================
 * Class Flowfield:	Class for flow field processing
 *					Read file -> Construction -> Initialization ->
 *					Get the time step -> Set the boundary -> Update
 *=================================================================================*/

#ifndef FlowField
#define FlowField

/*---------------------------------------------------------------------------------
 * Standard C++ library headers
 *---------------------------------------------------------------------------------*/

#include <iostream>

/*---------------------------------------------------------------------------------
 * Local headers
 *---------------------------------------------------------------------------------*/

#include "Array.h"
#include "TimeAdv.h"
#include "Reaction.h"
#include "Function.h"

using namespace std;

class Flowfield
{
private:
	/* x axis */
	int ni;                             /* Number of nodes */
	Array<double> xnode; 				/* The mesh nodes */
	double dx;			 				/* The mesh spacing */

	/* y axis */			
	int nj;				 				/* Number of nodes */
	Array<double> ynode; 				/* The mesh nodes */
	double dy;			 				/* The mesh spacing */

	int bc;								/* The number of each boundary grid */

	double dt;	 						/* The time step */
	double time; 						/* The real time */

	int NS;					  			/* Number of species */
	int NR;					  			/* Number of reactions */
	Reaction React;			  			/* Class Reaction -> Object React */
	const double R = 8.31434; 			/* gas constant of ideal gas J/(mol*K) */
	Array<double> Mw;					/* Component molecular weight */
	Array<double> Ri;					/* Component gas constant */
	Array<double> Coeff0;				/* NASA Thermochemical polynomial coefficient (T<1000) */
	Array<double> Coeff1;				/* NASA Thermochemical polynomial coefficient (T>1000) */

	TimeAdv Time; 						/* Class TimeAdv -> Object Time */
	double V3;
	double Mach;
	double Ujet,Vjet,Pjet,Tjet,Ljet;
	Array<double> Yjet;
	double cita;		 				/* The wedge angle */
	Array<double> U;					/* U velocity */
	Array<double> V;					/* V velocity */
	Array<double> P;					/* Pressure */
	Array<double> D;					/* Density */
	Array<double> T;					/* Temperature */
	Array<double> C;					/* Sound speed */
	Array<double> Ma;					/* Mach number */
	Array<double> Wav;					/* Average molecule weight */
	Array<double> Rgas;					/* Constant number of gas */
	Array<double> Cp;					/* The specific heat at constant pressure */
	Array<double> H;					/* Enthalpy */
	Array<double> E;					/* Internal energy */
	Array<double> Gamma;				/* Specific heat ratio */
	Array<double> Mr;					/* Component mole ratio */
	Array<double> Mc;					/* Component mole concentration */
	Array<double> Mi;					/* Component mole fraction */
	Array<double> Yi;					/* Component mass fraction */
	Array<double> Di;					/* Component density fraction */
	Array<double> Cpi;					/* The specific heat at constant pressure of each component */
	Array<double> Hi;					/* Enthalpy of each component */
	Array<double> Ei;					/* Internal energy of each component */

	Array<double> F;  					/* Flux at x direction */
	Array<double> G;  					/* Flux at y direction */
	Array<double> CS; 					/* Conserved variables */

	Function Fun; 						/* Class Function -> Object Fun */

	/* Freestream boundary */
	Array<double> Uint, Vint, Pint, Dint, Tint, Hint, Eint, Gint, Yint;

	/* Intermediate variables */
	Array<double> Yi_temp0;
	Array<double> PLR, DLR, ULR, VLR, HLR, GLR, YLR, Yi_temp, YL_temp, YR_temp, YL, YR;

	Array<double> Partial_T; 			/* Partial T */
	Array<double> RHS;		 			/* Residual */

	/*MPI variables */
	Array<double> send_data, recv_data;

	/* WENO-RK3 Test */
	Array<double> UC, UUC, UCC;
	Array<double> AM;
	Array<double> FX;
	Array<double> EVR, EVL;
	Array<double> AA, FK, FH;
	Array<double> GG, HHH, FF, FFF;
	Array<double> FHL, FHR, LUS;
	Array<double> YM;
	Array<double> H_old, Gamma_old;

public:
	friend class Euler; 				/* Friend class -> access to use private object */

	/* Constructor */
	Flowfield() = default;

	/* Read the input file */
	void InputRead(char *initialization, Array<double> xnode, Array<double> ynode, int bc);

	/* Construct the flow field */
	void Construction();

	/* Initialize the flow field */
	void FieldInitial(Array<double> Ri, Array<double> Mw, Array<double> Mi_temp, Array<double> Yi_temp, Array<double> Coeff0, Array<double> Coeff1);

	/* Get the time step */
	void CFLcondition_MPI(int myid,double cfl, double Final_Time);

	/* Set the boundary condition */
	void FieldBoundary_MPI(int id, int MPI_size);

	/*Set the MPI boundary condition*/
	void MPIBoundary(int id, int MPI_size);
	void MPIdataInit(int MPI_size);

	/* Solve the advection term */
	void Advection(int, int);

	/* Update after solving the advection term */
	void Update_after_Adv();

	/* Update the flow field after obtaining Di */
	void Explicit();
	void Explicit(Array<double> Nchem, int step);

	/* Update the flow field */
	void Update_IMEX(Array<double>, Array<double>);

	/* Update after the Conserved variables */
	void Update_after_CS();
	void Update_after_CS(Array<double> Nchem, int step);

	/* Destructor */
	~Flowfield() { ; };

	/* AUSM */
	void AUSM(int, Array<double>&, void (*Diff)(int, Array<double>, Array<double>, Array<double>&, Array<double>&, int, int));

	/* Get the temperature by Newton iteration */
	double Get_temp(double, int, int);

	/* Get the Partial_T */
	void GetPartial_T();

	/* WENO-RK3 Test */
	void Boundary_X(int);

	void SweepX();

	void Boundary_Y();

	void SweepY();

	void DFWENO(int, int);

	void RK3(int, int);

	void EigenvalueX(int, int, int);

	void EigenvalueY();

	//MPI TEST by zxk
	double MPI_TEST();
};
#endif